#include "rc.driver.h"
#include "rc.tab.hpp"
#include "rc.routine.h"
#include <string.h>
typedef void* yyscan_t;
rc_driver::rc_driver()
{
}
rc_driver::~rc_driver()
{
}

int rc_driver::parse(const std::string &f ,struct ast** a)
{
  int res = 0 ;
  file = f;
  input_type = 'f';
  res = scan_begin ();
  if ( res != 0 )
  {
    scan_end ();
    return res;
  }
  res = yyparse (yyscanner,a);
  scan_end ();
  return res;
}

int rc_driver::parse_string(const std::string &str , struct ast** a)
{
  int res = 0 ;
  string = str;
  input_type = 'b';
  res = scan_begin ();
  if ( res != 0 )
  {
    scan_end ();
    return res;
  }
  res = yyparse (yyscanner,a);
  scan_end ();
  return res;
}

int rc_driver:: check(const elem_t& e , struct ast* a)
{
  return 0;
}

struct termval {
  int type;
  int pos;
  union {
    double d;
    long l;
    char* s;
  } v;
};

int logic_val(termval val) 
{
  if ( val.type == ntype_str && val.v.s[0] != 0 ) // 非空字符串为真
  { 
     return 1;
  }
  else if ( val.type == ntype_int ) // 整型非0为真
  {
    return val.v.l != 0 ;
  }
  else if ( val.type == ntype_float ) // 浮点型永远为真
  {
    return val.v.d != 0.0 ;
  }
  return 0; // 未知类型为假
}
int eval_logic(int type , termval val1 , termval val2  , int * val)
{
  int out ;
  int v1 = logic_val(val1);
  int v2 = logic_val(val2);
  switch(type)
  {
      case ntype_or:
        *val = v1 || v2;
        break;
      case ntype_nand:
        *val = !(v1 && v2);
        break;
      case ntype_and:
        *val = v1 && v2;
        break;
      case ntype_not:
        *val = ! v1 ;
        break;
     default:
      return -1;
  }
  return 0;
}
int eval_cmp(int type , termval val1 , termval val2  , int * val)
{
  int cmp ;
  double cmp_double;
  if ( val1.type == ntype_str && val2.type == ntype_str)
  {
     cmp = strcmp( val1.v.s ,  val2.v.s);
  }
  else if ( val1.type == ntype_int && val2.type == ntype_int)
  {
    cmp = val1.v.l - val2.v.l;
  }
  else if ( val1.type == ntype_float && val2.type == ntype_float)
  {
    cmp_double = (val1.v.d - val2.v.d);
    cmp = (cmp_double > 0.0001) ? 1 :(cmp_double < -0.0001)?-1:0 ;
  }
  else if ( val1.type == ntype_float && val2.type == ntype_int)
  {
    cmp_double = (val1.v.d - val2.v.l);
    cmp = (cmp_double > 0.0001) ? 1 :(cmp_double < -0.0001)?-1:0 ;
  }
  else if ( val1.type == ntype_int && val2.type == ntype_float)
  {
    cmp_double = (val1.v.l - val2.v.d);
    cmp = (cmp_double > 0.0001) ? 1 :(cmp_double < -0.0001)?-1:0 ;
  }
  else
  {
    yyerror("can't compare type[%s] with type[%s] at pos[%d]" , gettypename(val1.type),gettypename(val2.type), val1.pos);
    return -1;
  }
  switch(type)
  {
      case ntype_gt:
        *val = cmp > 0;
        break;
      case ntype_lt:
        *val = cmp < 0;
        break;
      case ntype_ne:
        *val = cmp != 0;
        break;
      case ntype_eq:
        *val = cmp == 0;
        break;
      case ntype_ge:
        *val = cmp >= 0;
        break;
      case ntype_le:
        *val = cmp <= 0;
        break;
     default:
      return -1;
  }
  return 0;
}

int eval_iner(const elem_t& e , struct ast* a , termval* val)
{
  int res = 0 ;
  int cmp_flag = 0;
  int logic_flag = 0;
  int opval;
  struct termval val1={0}  ; 
  struct termval val2={0} ;
  if ( a==NULL )
  {
      val->type = ntype_int;
      val->v.l  = 0;
      return -1;
  }
  switch(a->nodetype)
  {
      case ntype_gt:
      case ntype_lt:
      case ntype_ne:
      case ntype_eq:
      case ntype_ge:
      case ntype_le:
         cmp_flag = 1;
      case ntype_or:
      case ntype_nand:
      case ntype_and:
        {
            res = eval_iner( e , a->r , &val2);
            if ( res != 0 ) return res;
        }
      case ntype_not:
        {
            logic_flag = 1;
            res = eval_iner( e , a->l , &val1);
            if ( res != 0 )
                return res;
            val->type = ntype_int;
            if ( cmp_flag )
              { res  = eval_cmp(a->nodetype , val1 , val2 , &opval); }
            else if ( logic_flag )
              { res  = eval_logic(a->nodetype , val1 , val2 , &opval); }
            if ( res != 0 ) return res;
            val->v.l  = opval ;
        }
          break;         
      case ntype_int:
          val->type = ((intval*)a)->nodetype;
          val->pos  = ((intval*)a)->pos;
          val->v.l  = ((intval*)a)->val;
          break;         
      case ntype_float:
          val->type = ((floatval*)a)->nodetype;
          val->pos  = ((floatval*)a)->pos;
          val->v.d  = ((floatval*)a)->val;
          break;       
      case ntype_fn:
        // TODO: 函数功能
        // 函数暂未支持 ,永远返回真
          val->type = ntype_int;
          val->pos  = ((fncall*)a)->pos;
          val->v.l  = 1;
          break;          
      case ntype_name:
        {
          char* innerstr ;
          innerstr = ((strval*)a)->val;
          elem_t::const_iterator elem_it ;
          elem_it = e.find(innerstr); 
          if (elem_it != e.end())
          {
            val->type = ntype_str;
            val->pos  = ((strval*)a)->pos;
            val->v.s  = (char*)elem_it->second.c_str();
          }
          else
          {
            yyerror("symbol %s not define",innerstr);
            return -1;
          }
        }
          break;        
      case ntype_str:
          val->type = ((strval*)a)->nodetype;
          val->pos  = ((strval*)a)->pos;
          val->v.s  = ((strval*)a)->val;
          break;         
      default:
          return -1;
  }
  return res;
}

int rc_driver:: eval(const elem_t& e , struct ast* a , int* val)
{
    struct termval x;
    int res = eval_iner( e , a , &x);
    *val = logic_val(x);
    return res;
}
